#pragma once

#ifndef __misc_H
#define __misc_H



#include <opencv2/opencv.hpp>
#include <vector>

using namespace cv;
using namespace std;

template<typename T>
void transformPointsForward(vector<Point2f>&origin,vector<Point_<T>>&dst, const Matx33d &H,vector<int> &unmask,bool isBox,const Rect &box);
template<typename T>
void transformPointsInverse(vector<Point2f>&origin,vector<Point_<T>> &dst,const Matx33d &H,vector<int> &unmask,bool isBox,const Rect &box);
void transformPointsInverse(vector<Point2f>&origin, const Matx33d &H,bool isBox=false,const Rect &box=Rect());
void transformPointsForward(vector<Point2f>&origin, const Matx33d &H,bool isBox=false,const Rect &box=Rect());

void transformPointsForward(const vector<KeyPoint>&origin, vector<KeyPoint> &dst, const Matx33d&H);
void transformPointsInverse(const vector<KeyPoint> &origin, vector<KeyPoint>&dst, const Matx33d&H);
void setPyramid(const Mat &img, const int levelsNum, const float scaleFactor, vector<Mat> &imagePyramid);
void warpScale(const Mat&src, Mat&dst, const Matx33d H, float _scale, int level);

template<typename T>
void transformPointsForward(vector<Point2f>&origin,vector<Point_<T>>&dst, const Matx33d &H,vector<int> &unmask,bool isBox,const Rect &box)
{
    dst.clear();
    dst.reserve(origin.size());
    const double *aa = H.val;
    for (int i = 0; i<origin.size(); i++)
    {
        auto &a = origin[i];
        double s = aa[6] * a.x + aa[7] * a.y + aa[8];
        Point_<T> aaa;
        aaa.x = (aa[0] * a.x + aa[1] * a.y + aa[2]) / s;
        aaa.y = (aa[3] * a.x + aa[4] * a.y + aa[5]) / s;
        if (isBox)
        {
            if (box.contains(aaa))
            {
                dst.push_back(aaa);
            }
            else
                unmask.push_back(i);
        }
        else
            dst.push_back(aaa);
    }
}

template<typename T>
void transformPointsInverse(vector<Point2f>&origin,vector<Point_<T>> &dst,const Matx33d &H,vector<int> &unmask,bool isBox,const Rect &box)
{
    Matx33d invH;
    invert(H, invH);
    dst.clear();
    dst.reserve(origin.size());
    const double *aa = invH.val;
    for (int i = 0; i<origin.size(); i++)
    {
        auto &a = origin[i];
        double s = aa[6] * a.x + aa[7] * a.y + aa[8];
        Point_<T> aaa;
        aaa.x = (aa[0] * a.x + aa[1] * a.y + aa[2]) / s;
        aaa.y = (aa[3] * a.x + aa[4] * a.y + aa[5]) / s;
        if (isBox)
        {
            if (box.contains(aaa))
            {
                dst.push_back(aaa);
            }
            else
            {
                unmask.push_back(i);
            }
        }
        else
            dst.push_back(aaa);
    }
}





#endif